using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using CustomCMS.API.Util;

namespace CustomCMS.QA
{
    [TestFixture]
    public class TestSolveIf
    {
        SolveIf Solver;

        [SetUp]
        public void SetUp()
        {
            Dictionary<string, string> values = new Dictionary<string,string>();
            values["s1"] = "Hello World!";
            values["s2"] = "!Ola";
            values["f1"] = "3.5";
            values["f2"] = "-4";
            values["f3"] = "0";
            values["b1"] = "true";
            values["b2"] = "false";
            values["e1"] = "";
            values["e2"] = null;
            Solver = new SolveIf(new Dictionary<string, string[]>(), values);
        }

        private void test(string t, string expectedResult)
        {
            Assert.AreEqual(expectedResult, Solver.SolveTest(t));
        }

        private void testIf(string t, string expectedResult)
        {
            StringBuilder s = new StringBuilder(t);
            Solver.Solve(s);
            Assert.AreEqual(expectedResult, s.ToString());
        }

        [Test] public void TestTrue() { test("true", "true"); }
        [Test] public void TestFalse() { test("false", "false"); }
        [Test] public void TestOne() { test("1", "true"); }
        [Test] public void TestMinusOne() { test("-1", "true"); }
        [Test] public void TestZero() { test("0", "false"); }
        [Test] public void TestEmpty() { test("", "false"); }
        [Test] public void TestNull() { test(null, "false"); }
        [Test] public void TestNo() { test("no", "false"); }
        [Test] public void TestNot() { test("not", "false"); }
        [Test] public void TestStringWithNull() { test("null", "false"); }
        [Test] public void TestYes() { test("yes", "true"); }
        [Test] public void TestLeadingSpaces() { test(" \t  \n \ttrue", "true"); }
        [Test] public void TestTrailingSpaces() { test("true \t  \n \t", "true"); }
        [Test] public void TestAllCaps() { test("TRUE", "true"); }
        [Test] public void TestParenthesis() { test("(  true \t\n)", "true"); }
        [Test] public void TestNegateFalse() { test(" \t  \n !\t\nfalse", "true"); }
        [Test] public void TestNegateTrue() { test(" \t  \n \t!true", "false"); }
        [Test] public void TestNegateParenthesis() { test("!( false)", "true"); }
        [Test] public void TestAndTrue() { test("true \n&&yes", "true"); }
        [Test] public void TestAndFalse() { test("false&&\ntrue", "false"); }
        [Test] public void TestAndNumbers() { test("1&&\n-1", "true"); }
        [Test] public void TestOrTrue() { test("false \n||yes", "true"); }
        [Test] public void TestOrFalse() { test("false||\nno", "false"); }
        [Test] public void TestOrNumbers() { test("0||\n-1", "true"); }
        [Test] public void TestOrNegate() { test("-1||\n!0", "true"); }
        [Test] public void TestAndNegate() { test("!\n0&&\n! false && !not", "true"); }
        [Test] public void TestMultiplateNegates() { test("!\n!\t !0&&\n!!   !!-1", "true"); }
        [Test] public void TestMultipleAnd() { test("true && yes && 1", "true"); }
        [Test] public void TestMultipleOr() { test("false||\n0\t||no", "false"); }
        [Test] public void TestMultipleNegates() { test("!\n\t! !false", "true"); }
        [Test] public void TestComplexAndOrNegate() { test("true && !((false) && !!(1||0) || no)", "true"); }

        [Test] public void TestVarB1() { test("b1", "true"); }
        [Test] public void TestVarB2() { test("\t\nb2 ", "false"); }
        [Test] public void TestVarF1() { test("f1", "true"); }
        [Test] public void TestVarF2() { test("\t\nf2 ", "true"); }
        [Test] public void TestVarF3() { test("\t\nf3 ", "false"); }
        [Test] public void TestVarS1() { test("s1", "true"); }
        [Test] public void TestVarS2() { test("\t\ns2 ", "true"); }
        [Test] public void TestVarE1() { test("e1", "false"); }
        [Test] public void TestVarE2() { test("\t\ne2 ", "false"); }

        [Test] public void TestAndTrueVars() { test("b1 \n&&b1", "true"); }
        [Test] public void TestAndFalseVars() { test("b2&&\nb1", "false"); }
        [Test] public void TestAndNumberVars() { test("f2&&\nf1", "true"); }
        [Test] public void TestAndStringVars() { test("s2&&\ns1", "true"); }
        [Test] public void TestAndEmptyVars() { test("e1&&\ns1", "false"); }
        [Test] public void TestOrTrueVars() { test("b2 \n||b1", "true"); }
        [Test] public void TestOrFalseVars() { test("b2||\nf3", "false"); }
        [Test] public void TestOrNumberVars() { test("f3||\nf2", "true"); }
        [Test] public void TestOrStringVars() { test("s2||\ne1", "true"); }
        [Test] public void TestOrEmptyVars() { test("e1||\ne2", "false"); }
        [Test] public void TestMultipleAndVars() { test("b1 && s2 && f2", "true"); }
        [Test] public void TestMultipleOrVars() { test("e1||\ne2\t||b2||f3", "false"); }
        [Test] public void TestComplexAndOrNegateVars() { test("s2 && !((e2) && !!(f2||e1) || f3)", "true"); }

        [Test] public void TestNegateVarB1() { test("!b1", "false"); }
        [Test] public void TestNegateVarB2() { test("\t!\nb2 ", "true"); }
        [Test] public void TestNegateVarF1() { test("!f1", "false"); }
        [Test] public void TestNegateVarF2() { test("!\t\nf2 ", "false"); }
        [Test] public void TestNegateVarF3() { test("!\t\nf3 ", "true"); }
        [Test] public void TestNegateVarS1() { test("!s1", "false"); }
        [Test] public void TestNegateVarS2() { test("\t!\ns2 ", "false"); }
        [Test] public void TestNegateVarE1() { test("!e1", "true"); }
        [Test] public void TestNegateVarE2() { test("\t!\ne2 ", "true"); }

        [Test] public void TestEqualStringsEquality() { test("abc== abc", "true"); }
        [Test] public void TestEqualStringsInequality() { test(" abc !=abc", "false"); }
        [Test] public void TestInequalStringsEquality() { test("abc== abcd", "false"); }
        [Test] public void TestInequalStringsInequality() { test(" abc !=abcd", "true"); }
        [Test] public void TestEqualStringsBiggerOrEqual() { test("abc >= abc", "true"); }
        [Test] public void TestEqualStringsBigger() { test(" abc >abc", "false"); }
        [Test] public void TestEqualStringsSmallerOrEqual() { test("abc <= abc", "true"); }
        [Test] public void TestEqualStringsSmaller() { test(" abc <abc", "false"); }
        [Test] public void TestInequalStringsBiggerOrEqual() { test("abc >= abcd", "false"); }
        [Test] public void TestInequalStringsBigger() { test(" abc >abcd", "false"); }
        [Test] public void TestInequalStringsSmallerOrEqual() { test("abc <= abcd", "true"); }
        [Test] public void TestInequalStringsSmaller() { test(" abc <abcd", "true"); }

        [Test] public void TestEqualNumbersEquality() { test("3== 3", "true"); }
        [Test] public void TestEqualNumbersInequality() { test(" 3 !=3", "false"); }
        [Test] public void TestInequalNumbersEquality() { test("3== 13.4", "false"); }
        [Test] public void TestInequalNumbersInequality() { test(" 3 !=13.4", "true"); }
        [Test] public void TestEqualNumbersBiggerOrEqual() { test("3 >= 3", "true"); }
        [Test] public void TestEqualNumbersBigger() { test(" 3 >3", "false"); }
        [Test] public void TestEqualNumbersSmallerOrEqual() { test("3 <= 3", "true"); }
        [Test] public void TestEqualNumbersSmaller() { test(" 3 <3", "false"); }
        [Test] public void TestInequalNumbersBiggerOrEqual() { test("3 >= 13.4", "false"); }
        [Test] public void TestInequalNumbersBigger() { test(" 3 >13.4", "false"); }
        [Test] public void TestInequalNumbersSmallerOrEqual() { test("3 <= 13.4", "true"); }
        [Test] public void TestInequalNumbersSmaller() { test(" 3 <13.4", "true"); }

        [Test] public void TestEqualBoolsEquality() { test("true== TRUE", "true"); }
        [Test] public void TestEqualBoolsInequality() { test(" false !=FALSE", "false"); }
        [Test] public void TestInequalBoolsEquality() { test("true== false", "false"); }
        [Test] public void TestInequalBoolsInequality() { test(" true !=false", "true"); }
        [Test] public void TestEqualBoolsBiggerOrEqual() { test("true >= TRUE", "true"); }
        [Test] public void TestEqualBoolsBigger() { test(" true >TRUE", "false"); }
        [Test] public void TestEqualBoolsSmallerOrEqual() { test("true <= TRUE", "true"); }
        [Test] public void TestEqualBoolsSmaller() { test(" true <TRUE", "false"); }
        [Test] public void TestInequalBoolsBiggerOrEqual() { test("false >= true", "false"); }
        [Test] public void TestInequalBoolsBigger() { test(" false >true", "false"); }
        [Test] public void TestInequalBoolsSmallerOrEqual() { test("false <= true", "true"); }
        [Test] public void TestInequalBoolsSmaller() { test(" false <true", "true"); }

        [Test] public void TestEqualStringVarsEquality() { test("s1== s1", "true"); }
        [Test] public void TestEqualStringVarsInequality() { test(" s1 !=s1", "false"); }
        [Test] public void TestInequalStringVarsEquality() { test("s1== s2", "false"); }
        [Test] public void TestInequalStringVarsInequality() { test(" s1 !=s2", "true"); }
        [Test] public void TestEqualStringVarsBiggerOrEqual() { test("s1 >= s1", "true"); }
        [Test] public void TestEqualStringVarsBigger() { test(" s1 >s1", "false"); }
        [Test] public void TestEqualStringVarsSmallerOrEqual() { test("s1 <= s1", "true"); }
        [Test] public void TestEqualStringVarsSmaller() { test(" s1 <s1", "false"); }
        [Test] public void TestInequalStringVarsBiggerOrEqual() { test("s1 >= s2", "true"); }
        [Test] public void TestInequalStringVarsBigger() { test(" s1 >s2", "true"); }
        [Test] public void TestInequalStringVarsSmallerOrEqual() { test("s1 <= s2", "false"); }
        [Test] public void TestInequalStringVarsSmaller() { test(" s1 <s2", "false"); }

        [Test] public void TestLeftVarRightStringEquality() { test("s2== '!Ola'", "true"); }
        [Test] public void TestLeftStringRightVarEquality() { test(" \"!Ola\"\n\n== s2", "true"); }
        [Test] public void TestLeftStringRightStringEquality() { test("\"!Ola\"==\n\n\t'!Ola'", "true"); }
        [Test] public void TestMixedStringVarsBigger() { test("s1> s2", "true"); }
        [Test] public void TestMixedStringVarsSmaller() { test("s1\t\t<s2", "false"); }
        [Test] public void TestMixedStringNumericVarsBigger() { test("s1> f1", "true"); }
        [Test] public void TestMixedStringNumericVarsSmaller() { test("s1< f1", "false"); }
        [Test] public void TestMixedNumericVarsEquality() { test(" f3 ==b2", "true"); }
        //[Test] public void TestMixedNumericVarsEquality2() { test(" b1 == f2", "true"); }
        //[Test] public void TestMixedNumericVarsEquality3() { test(" b2 == e1", "true"); }
        [Test] public void TestMixedVarsBiggerOrEqual() { test("f1 >= f2", "true"); }
        [Test] public void TestMixedVarsSmaller() { test(" f1 <f2", "false"); }
        [Test] public void TestMixedVarsBigger() { test(" -14.5 <f1", "true"); }
        [Test] public void TestMixedVarsSmallerOrEqual() { test(" -14.5 =>f1", "false"); }

        [Test] public void TestMalformed() { test(" hello world ", "<!--\n/* Malformed test condition in IF element:  hello world  *///-->"); }
        [Test] public void TestSingleWord() { test(" hello  ", "false"); }

        [Test] public void IfTrue() { testIf("<cms:if test='true'>A<cms:then>B</cms:then>C<cms:else>D</cms:else>E</cms:if>", "ABCE"); }
        [Test] public void IfFalse() { testIf("<cms:if test='false'>A<cms:then>B</cms:then>C<cms:else>D</cms:else>E</cms:if>", "ACDE"); }
        [Test] public void IfEmpty() { testIf("<cms:if test=''>A<cms:then>B</cms:then>C<cms:else>D</cms:else>E</cms:if>", "ACDE"); }
        [Test] public void IfWithoutTest() { testIf("<cms:if>A<cms:then>B</cms:then>C<cms:else>D</cms:else>E</cms:if>", ""); }
        [Test] public void IfTrueWithoutThen() { testIf("<cms:if test='true'>AC<cms:else>D</cms:else>E</cms:if>", "ACE"); }
        [Test] public void IfFalseWithoutThen() { testIf("<cms:if test='false'>AC<cms:else>D</cms:else>E</cms:if>", "ACDE"); }
        [Test] public void IfTrueWithoutElse() { testIf("<cms:if test='true'>A<cms:then>B</cms:then>CE</cms:if>", "ABCE"); }
        [Test] public void IfFalseWithoutElse() { testIf("<cms:if test='false'>A<cms:then>B</cms:then>CE</cms:if>", "ACE"); }
        [Test] public void IfTrueWithoutThenElse() { testIf("<cms:if test='true'>ACE</cms:if>", "ACE"); }
        [Test] public void IfFalseWithoutThenElse() { testIf("<cms:if test='false'>ACE</cms:if>", "ACE"); }
        [Test] public void IfWithoutTestThenElse() { testIf("<cms:if></cms:if>", ""); }
        [Test] public void IfWithEmptyElement() { testIf("<cms:if/>", ""); }
        [Test] public void IfWithSpaces() { testIf("<cms:if \t\ntest = 'true' \n>\n\tA\n\t<cms:then>\n\t\tB\n\t</cms:then>\n\tC\n\t<cms:else>\n\t\tD\n\t</cms:else>\n\tE\n</cms:if>", "\n\tA\n\t\n\t\tB\n\t\n\tC\n\t\n\tE\n"); }
    }
}
